﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Gqq.CSharpindepth2.CSharpBasic;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Gqq.UnitTest
{
    [TestClass]
    public class CovariantTest
    {
        //测试协变
        [TestMethod]
        public void TestCovariant()
        {
            //将返回值为Derived的匿名函数赋值给支持协变的委托。
            DelegateGenericClass2.Output<Basic> db = delegate()
                {
                    return new Derived { Name = "aaa" };
                };
            var result = db();
            //检查result的类型是不是Basic的。
            Assert.IsInstanceOfType(result, typeof(Basic));
            //检查result的Name属性
            Assert.AreEqual(result.Name, "aaa");
        }

        [TestMethod]
        public void TestCovariant2()
        {
            //将返回值为Derived的匿名函数赋值给支持协变的委托。
            DelegateGenericClass2.Output<Basic> db = DelegateGenericClass2.OutputD;
            var result = db();
            //检查result的类型是不是Basic的。
            Assert.IsInstanceOfType(result, typeof(Basic));
            Assert.IsInstanceOfType(result, typeof(Derived));
            //检查result的Name属性
            Assert.AreEqual(result.Name, "aaa");
        }

        public string OutputBasic(Basic b)
        {
            return b.Id + b.Name;
        }

        [TestMethod]
        public void TestContravariant()
        {
            //特别注意，这样使用逆变是不可以的。因为指定的参数是Derived类型，所以不能直接使用匿名函数
            //            DelegateGenericClass2.Input<Derived> d = delegate(Basic b) { return b.Name; };
            Derived b = new Derived { Name = "ttt", Id = 1 };
            DelegateGenericClass2.Input<Derived> d = OutputBasic;

            var result = d((Derived)b);
            Assert.AreEqual(result, "1ttt");
        }



        [TestMethod]
        public void TestInterfaceContravariant()
        {
            //在逆变中，方法的参数是basic，完全可以传入derived参数。因此，可以使用如下方法。
            //IProcess<Derived2>要求传入Process的参数必须是Derived2类型的，BasicProcess要求传入的参数必须是basic的。
            IProcess<Derived2> id = new BasicProcess();
            Derived2 dv2 = new Derived2 { Id = 1, Name = "sss" };
            id.Process(dv2);
        }

        [TestMethod]
        public void TestInterfaceCovariant()
        {
            IInfo<Basic> ib = new DerivedInfo();
            var derived = ib.GetInfo();

            Assert.IsInstanceOfType(derived, typeof(Basic));
            Assert.IsInstanceOfType(derived, typeof (Derived2));
            var de = derived as Derived2;
            Assert.IsNotNull(de);
            Assert.AreEqual(de.Addtional, "sss");
        }
    }
}
